<template>
  <div class="t-gen-form">
    <el-row :gutter="formConfCopy.gutter">
      <el-form
        :ref="formConfCopy.formRef"
        :disabled="formConf.disabled"
        :label-position="formConfCopy.labelPosition"
        :label-width="formConfCopy.labelWidth + 'px'"
        :model="formModel"
        :rules="formRules"
        :size="formConfCopy.size"
      >
        <generate-form-item
          v-for="(item, index) in formConfCopy.fields"
          :key="`${item.key}_${index}`"
          :cid="item.vModel"
          :index="index"
          :item="item"
          :models.sync="formModel"
          :rules="formRules"
          :seq-no="getSeqNo(index, item)"
          :style="isFieldShow(item)"
          @next="nextPage"
          @prev="prevPage"
          @input-change="onInputChange"
          @ocr-success="handleOcrSuccess"
        />

        <el-col v-if="formConfCopy.formBtns">
          <el-form-item class="submit-btn-form-item" size="large" style="margin-top: 30px">
            <el-button v-if="showSubmitBtn" type="primary" :loading="btnLoading" @click="submitForm">
              {{ formConfCopy.theme && formConfCopy.theme.submitBtnText ? formConfCopy.theme.submitBtnText : '提交' }}
            </el-button>
            <el-button v-if="formConfCopy.resetBtn" @click="resetForm"> 重置 </el-button>
          </el-form-item>
        </el-col>
      </el-form>
    </el-row>
  </div>
</template>

<script>
import { handleChangeLabel } from './FormItemLabel'
import _ from 'lodash'
import '../FormItem/autoRegister.js'
import { evalExpression } from '../../utils/expression'
import { execRemoteAPI } from '../../api/execRemoteAPI'
import GenerateFormItem from './GenerateFormItem'
import { throttle } from 'throttle-debounce'
import FormValidateRule from './FormValidateRule'
import { saveFormData } from '../../utils/db'

let seqNo = 0

export default {
  name: 'GenerateForm',
  components: {
    GenerateFormItem
  },
  mixins: [FormValidateRule],
  props: {
    formConf: {
      type: Object,
      required: true
    },
    // 被触发了逻辑显示的字段列表
    logicTriggerItemList: {
      type: Array,
      required: false
    },
    pageFormModel: {
      type: Object,
      required: false
    }
  },
  data() {
    return {
      // 维护一个对象存储 字段名和字段的index 避免查找
      fieldIdIndex: {},
      formConfCopy: _.cloneDeep(this.formConf),
      formModel: _.cloneDeep(this.pageFormModel),
      formRules: {},
      btnLoading: false
    }
  },
  computed: {
    showSubmitBtn() {
      if (!this.formConfCopy.theme) {
        return true
      }
      if (this.formConfCopy.theme && false == this.formConfCopy.theme.showSubmitBtn) {
        return false
      }
      return true
    }
  },
  created() {
    console.log(this.formConf.fields)
    // 初始化动态数据 比如SELECT等远程数据
    this.initDynamicOptions(this.formConfCopy.fields)
    // 初始化默认值
    this.initFormData(this.formConfCopy.fields, this.formModel)
    // 构建表单校验规则
    this.buildRules(this.formConfCopy.fields, this.formRules)
    // 特殊处理分页
    seqNo = this.formConfCopy.startSeqNo || 0
  },
  mounted() {},
  methods: {
    getKey() {
      return new Date()
    },
    // 初始化表单动态选项
    async initDynamicOptions(componentList) {
      for (const cur of componentList) {
        const config = cur.config
        // 数据为从接口获取
        if (config.optionsType && config.optionsType === 1) {
          execRemoteAPI.get(config.dynamicOptions.url).then((res) => {
            const options = _.get(res.data, config.dynamicOptions.dataPath)
            if (options && _.isArray(options)) {
              const dyOptions = options.map((op) => ({
                value: _.get(op, config.dynamicOptions.valueField),
                label: _.get(op, config.dynamicOptions.labelField)
              }))
              console.log(dyOptions)
              config.options = dyOptions
            }
          })
        }
        // 从字典获取
        if (config.optionsType && config.optionsType === 2) {
          let dictRes = await execRemoteAPI.get(`/system/dict/data/type/${config.dictOptionType}`)
          config.options = dictRes.data.data.map((op) => ({
            value: op.dictValue,
            label: op.dictLabel
          }))
        }
      }
    },
    // 初始化表单默认值
    initFormData(componentList, formData) {
      // 设置默认值
      componentList.forEach((cur, index) => {
        const config = cur.config
        this.fieldIdIndex[cur.vModel] = index
        // 如果存在分页带回的数据 则不再设置默认 0是checkbx radio等的其他输入框
        if (cur.vModel && !formData[cur.vModel] && 0 != formData[cur.vModel]) {
          formData[cur.vModel] = config.defaultValue
          handleChangeLabel(formData, cur, config.defaultValue)
          // 处理默认值的逻辑
          if (config.defaultValue !== undefined && config.defaultValue !== null) {
            this.logicShowHandle(config.defaultValue, cur.vModel, {})
          }
        }
        if (config.children) this.initFormData(config.children, formData)
      })
    },
    // 表单校验规则
    buildRules(componentList, rules) {
      componentList.forEach((cur) => {
        // 逻辑不显示必填问题不校验
        const triggerShow = _.indexOf(this.logicTriggerItemList, cur.formItemId) > -1
        // cur.logicShow 是否逻辑显示字段  triggerShow 已经被触发显示的问题
        // 是逻辑显示字段  并且还没满足条件被显示·
        if (cur.logicShowField !== true || triggerShow) {
          this.buildRule(cur, rules)
        }
      })
    },
    removeRule(cur) {
      delete this.formRules[cur.vModel]
    },
    resetForm() {
      this.formConfCopy = _.cloneDeep(this.formConf)
      this.$refs[this.formConf.formRef].resetFields()
    },
    submitForm: throttle(3000, true, function () {
      this.$refs[this.formConf.formRef].validate((valid) => {
        if (!valid) {
          // 未选中自动高亮
          // if (document.getElementsByClassName('el-FormItem-item__error').length > 0) {
          //
          // }
          // console.log(valid);
          setTimeout(() => {
            const isError = document.getElementsByClassName('is-error')
            isError[0].querySelector('input')?.focus()
          }, 100)
          return false
        }
        //开始loading 1s后关闭
        this.btnLoading = true
        setTimeout(() => {
          this.btnLoading = false
        }, 1000)
        // 触发submit事件
        console.log(JSON.stringify(this.formModel))
        this.$emit('submit', { formModel: this.formModel })
        return true
      })
    }),
    /**
     *  表单发生值变化
     * @param value 值
     * @param field 字段名
     * @param item  发生改变表单组件对象
     */
    onInputChange(value, field, item) {
      this.$emit('on-change', field, value, this.models)
      this.logicShowHandle(value, field, item)
      //临时存储数据到本地 下次进入可以选择回显
      this.tempSaveFormData()
    },
    /**
     * 分页下一页
     */
    nextPage(page) {
      this.switchPage('next', page)
    },

    /**
     * 分页上一页
     */
    prevPage(page) {
      this.switchPage('prev', page)
    },
    /**
     * 切换页
     */
    switchPage(eventName, page) {
      this.$refs[this.formConf.formRef].validate((valid) => {
        if (!valid) {
          setTimeout(() => {
            const isError = document.getElementsByClassName('is-error')
            isError[0].querySelector('input').focus()
          }, 100)
          return false
        }
        this.$emit(eventName, {
          page,
          startSeqNo: this.formConfCopy.startSeqNo,
          endSeqNo: seqNo,
          formModel: this.formModel
        })
        return true
      })
    },
    // 字段是否能显示
    isFieldShow(item) {
      //不是逻辑显示字段
      if (!item.logicShowField) {
        return ''
      }
      // 表单被重新渲染 控制逻辑显示隐藏
      const triggerShow = _.indexOf(this.logicTriggerItemList, item.vModel) > -1
      //  或者已经被触发显示了
      return triggerShow ? '' : 'display:none'
    },
    getSeqNo(index, item) {
      //是否开启显示标题
      if (!this.formConfCopy.theme || this.formConfCopy.theme.showNumber !== true) {
        return null
      }
      // 处于显示状态并且组件不是辅助显示类型
      if (!this.isFieldShow(item) && item.displayType == false) {
        seqNo++
      }
      return seqNo
    },
    // 数据变更时 处理逻辑显示相关数据
    logicShowHandle(value, field, item) {
      seqNo = this.formConfCopy.startSeqNo || 0
      // 值被包装过 需要取出原始值
      const { logicShowRule } = this.formConfCopy
      if (!logicShowRule) {
        return
      }
      // 找到该问题需要触发显示的问题 判断逻辑是否成立
      const rules = _.get(logicShowRule, field)
      if (rules && Array.isArray(rules)) {
        rules.forEach((r) => {
          // 成立让该对应的问题显示出来
          const flag = evalExpression(this.formModel, r.logicExpression)
          if (flag) {
            // 显示加上值必填等校验
            let triggerFormItem = this.formConfCopy.fields[this.fieldIdIndex[r.triggerFormItemId]]
            // 重新渲染组件 不然必填红点不显示
            if (triggerFormItem) {
              triggerFormItem.key = new Date().getTime()
              this.buildRule(triggerFormItem, this.formRules)
              // 设置默认值
              this.$set(this.formModel, r.triggerFormItemId, triggerFormItem.config.defaultValue)
            }
            // 防止表单重新渲染 display被刷新
            this.logicTriggerItemList.push(r.triggerFormItemId)
            let triggerEle = document.querySelector(`div[cid="${r.triggerFormItemId}"]`)
            if (triggerEle) {
              triggerEle.style.display = ''
            }
          } else {
            _.remove(this.logicTriggerItemList, (n) => n === r.triggerFormItemId)
            // 移除表单的必填校验
            let triggerFormItem = this.formConfCopy.fields[this.fieldIdIndex[r.triggerFormItemId]]
            if (triggerFormItem) {
              this.removeRule(triggerFormItem)
            }
            // 移除已经填写的值
            delete this.formModel[r.triggerFormItemId]
            let triggerEle = document.querySelector(`div[cid="${r.triggerFormItemId}"]`)
            if (triggerEle) {
              triggerEle.style.display = 'none'
            }
          }
        })
      }
    },
    /**
     * OCR识别完成之后 把数据填充到表单内
     * @param val
     */
    handleOcrSuccess(val) {
      Object.keys(val).forEach((key) => {
        this.$set(this.formModel, key, val[key])
        //更改组件key 让组件重新渲染 不然数据不会显示到表单
        let item = this.formConfCopy.fields[this.fieldIdIndex[key]]
        item.key = new Date() + key
      })
    },
    /**
     * 临时存储到localstore
     */
    tempSaveFormData: throttle(430, true, function () {
      // 是否打开临时存储选项
      if (this.formConf.setting && this.formConf.setting.saveNotSubmitStatus) {
        saveFormData(this.formModel, this.formConf.formKey)
      }
    })
  }
}
</script>

<style lang="scss" scoped>
.submit-btn-form-item {
  text-align: center;
}
</style>
